`include "timescale.v"

module onu_rx (
	input 		   reset,						//need this ??
	input 		   Rx_clk, Rx_dv, Rx_er,		//GMII interface
	input  [7:0]   Rxd,


	// output 		   rx_frame_start, rx_frame_end;
	// output 		   rx_frame_we,	//write enable (for fifo)
	// output   rx_data_en,			
	output [4:0]   rx_state,
	output [15:0]  rx_byte_cnt,
	output 		   rx_fcs_ok,
	// output 		   rx_fcs_pre_ok,			//can't generate  !!
	input 		   rx_abort
	);
	
	// input  [47:0]  MAC,     					 //  Station Address  

	// output 		   StateData_o,
	// output reg [15:0] len_type,	
	// output		   ByteCntEq14, ByteCntEq15,

	// //signals for mac control
	// output reg 	   UnicastOK, BroadcastOK, MulticastOK,
	// output reg 	   MPCP_PAUSE_MultiAddr_OK,
	// output reg 	   OAM_MultiAddr_OK
// );
wire 			  RxdEq55, RxdEqD5;

assign 			  RxdEq55 	  = Rxd == 8'h55;
assign 			  RxdEqD5 	  = Rxd == 8'hd5;

wire 			  StartDrop, StartIdle, StartPreamble, StartSFD, StartData;
reg 			  StateDrop, StateIdle, StatePreamble, StateSFD, StateData;

assign 			  rx_state[4:0] = {StateDrop, StateIdle, StatePreamble, StateSFD, StateData};


// ==================== start of the counter of rx ====================
// ---------- Byte Counter
reg 	  [15:0]  ByteCnt;
wire 			  ResetByteCnt, IncrementByteCnt;
wire 			  ByteCntEq0, ByteCntEq1, ByteCntEq2, ByteCntEq3, ByteCntEq4, ByteCntEq5, ByteCntEq6, ByteCntEq7;
wire 			  ByteCntMax;			//what does this used for ???
wire 			  ByteCntMaxFrame;	
  
assign 			  ResetByteCnt = Rx_dv & (StateSFD & RxdEqD5 | StateData & ByteCntMaxFrame );
assign 			  IncrementByteCnt = ~ResetByteCnt & Rx_dv & (StatePreamble | StateSFD | StateIdle | StateData & ~ByteCntMax);
//ByteCnt
always@(posedge Rx_clk or posedge reset)
begin
  if(reset)
	ByteCnt <= 16'd0;
  else begin
	if(ResetByteCnt)
	  ByteCnt <= 16'd0;
	else if(IncrementByteCnt)
	  ByteCnt <= ByteCnt + 16'd1;
  end
end

assign 			  rx_byte_cnt = ByteCnt;

assign 			  ByteCntEq0  = ByteCnt == 16'd0;
assign 			  ByteCntEq1  = ByteCnt == 16'd1;
assign 			  ByteCntEq2  = ByteCnt == 16'd2;
assign 			  ByteCntEq3  = ByteCnt == 16'd3;
assign 			  ByteCntEq4  = ByteCnt == 16'd4;
assign 			  ByteCntEq5  = ByteCnt == 16'd5;
assign 			  ByteCntEq6  = ByteCnt == 16'd6;
assign 			  ByteCntEq7  = ByteCnt == 16'd7;
assign 			  ByteCntLtEq5  = ByteCnt <= 16'd5;
// assign 			  ByteCntMaxFrame = ByteCnt == MaxFL[15:0] & ~HugEn;
assign 			  ByteCntMaxFrame = ByteCnt == 16'd1500;
assign 			  ByteCntMax  = ByteCnt == 16'hffff;
//the length/type field			-- to check it when ByteCnt>=14
assign 			  ByteCntEq12  = ByteCnt == 16'd12;
assign 			  ByteCntEq13  = ByteCnt == 16'd13;
assign 			  ByteCntEq14  = ByteCnt == 16'd14;
assign 			  ByteCntEq15 = ByteCnt == 16'd15;
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)
// 	len_type <= 16'd00;
//   else if(StateData & ByteCntEq12)
// 	len_type[15:8] <= Rxd;
//   else if(StateData & ByteCntEq13)
// 	len_type[7:0] <= Rxd;
// end

//---------- IFGcnt
reg 	  [3:0]   IFGcnt;
wire 			  IFGcntEq12;
wire 			  ResetIFGcnt, IncrementIFGcnt;

assign 			  ResetIFGcnt = StateSFD & Rx_dv & RxdEqD5  | StateDrop;
assign 			  IncrementIFGcnt = ~ResetIFGcnt & (StateDrop | StateIdle | StatePreamble | StateSFD) & ~IFGcntEq12;
always @ (posedge Rx_clk or posedge reset)
begin
  if(reset)
    IFGcnt <=  5'h0;
  else
    begin
      if(ResetIFGcnt)
        IFGcnt <=  5'h0;
      else
      if(IncrementIFGcnt)
        IFGcnt <=  IFGcnt + 5'd1;				//increase until equal to 12
    end
end
// assign 			  IFGcntEq12 = (IFGcnt[4:0] == 5'h18) | r_IFG; // 24*400 = 9600 ns or r_IFG is set to 1
assign 			  IFGcntEq12 = IFGcnt[3:0] == 4'd12;			//96'bits/8 = 12   //the reset value should be true ???
//////////////////// the end of rx counters ////////////////////

// ==================== start of the rx fsm ====================
assign 			  StartIdle   = ~Rx_dv & (StateDrop | StatePreamble | StateSFD | StateData);
assign 			  StartPreamble = Rx_dv & ~RxdEq55 & StateIdle;
assign 			  StartSFD 	  = Rx_dv & RxdEq55 & (StateIdle | StatePreamble);
assign 			  StartData   = Rx_dv & StateSFD & RxdEqD5 & IFGcntEq12; //after SFD or Data1 //why must IFGcntEq12
assign 			  StartDrop   = Rx_dv & (StateSFD & RxdEqD5 & ~IFGcntEq12 |  StateData & ByteCntMaxFrame);

always@(posedge Rx_clk or posedge reset)
begin
  if(reset) begin
	StateDrop <= 1'b1;
	StateIdle <= 1'b0;
	StatePreamble <= 1'b0;
	StateSFD <= 1'b0;
	StateData <= 1'b0;
  end
  else begin
	if(StartPreamble | StartSFD | StartDrop)
	  StateIdle <= 1'b0;
	else if(StartIdle)
	  StateIdle <= 1'b1;

	if(StartIdle)
	  StateDrop <= 1'b0;
	else if(StartDrop)
	  StateDrop <= 1'b1;

	if(StartIdle | StartSFD)
	  StatePreamble <= 1'b0;
	else if(StartPreamble)
	  StatePreamble <= 1'b1;

	if(StartIdle | StartDrop | StartData)
	  StateSFD <= 1'b0;
	else if(StartSFD)
	  StateSFD <= 1'b1;

	if(StartIdle | StartDrop)
	  StateData <= 1'b0;
	else if(StartData)
	  StateData <= 1'b1;
  end
end
//////////////////// end of rx fsm ////////////////////

//==================== start of addr check ====================

// wire 			  RxAddrValid;
// reg 			  RxAbort;
// wire 			  RxEndFrm;

// wire 	  [47:0]  MPCP_PAUSE_Multicast, OAM_Multicast;
// assign 			  MPCP_PAUSE_Multicast = 48'h0180C2000001;
// assign 			  OAM_Multicast = 48'h0180C2000002;


// // assign 			  RxAddrValid = UnicastOK | BroadcastOK | MulticastOK | r_Pro;
// assign 			  RxAddrValid = UnicastOK | BroadcastOK | MulticastOK | MPCP_PAUSE_MultiAddr_OK | OAM_MultiAddr_OK;
// // assign 			  BroadcastOK = Broadcast & ~r_Bro;			//why ??

// //for unicast 
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)				//reset or rxabort or rxendfrm !
// 	UnicastOK <= 1'b0;
//   else if(RxEndFrm | RxAbort)
// 	UnicastOK <= 1'b0;
//   else if(StateData)
//   begin
// 	if(ByteCntEq0)
// 	  UnicastOK <= Rxd == MAC[47:40];
// 	else if(ByteCntEq1)
// 	  UnicastOK <= Rxd == MAC[39:32] & UnicastOK;
// 	else if(ByteCntEq2)
// 	  UnicastOK <= Rxd == MAC[31:24] & UnicastOK;
// 	else if(ByteCntEq3)
// 	  UnicastOK <= Rxd == MAC[23:16] & UnicastOK;
// 	else if(ByteCntEq4)
// 	  UnicastOK <= Rxd == MAC[15:8] & UnicastOK;
// 	else if(ByteCntEq5)
// 	  UnicastOK <= Rxd == MAC[7:0] & UnicastOK;
//   end
// end

// //for control multicast addr
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)				//reset or rxabort or rxendfrm !
// 	MPCP_PAUSE_MultiAddr_OK <= 1'b0;
//   else if(RxEndFrm | RxAbort)
// 	MPCP_PAUSE_MultiAddr_OK <= 1'b0;
//   else if(StateData)
//   begin
// 	if(ByteCntEq0)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[47:40];			//the MPCP/PAUSE/OAM has the the same mutlicast addr [47:8]
// 	else if(ByteCntEq1)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[39:32] & MPCP_PAUSE_MultiAddr_OK;
// 	else if(ByteCntEq2)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[31:24] & MPCP_PAUSE_MultiAddr_OK;
// 	else if(ByteCntEq3)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[23:16] & MPCP_PAUSE_MultiAddr_OK;
// 	else if(ByteCntEq4)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[15:8] & MPCP_PAUSE_MultiAddr_OK;
// 	else if(ByteCntEq5)
// 	  MPCP_PAUSE_MultiAddr_OK <= Rxd == MPCP_PAUSE_Multicast[7:0] & MPCP_PAUSE_MultiAddr_OK;
//   end
// end

// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)				//reset or rxabort or rxendfrm !
// 	OAM_MultiAddr_OK <= 1'b0;
//   else if(RxEndFrm | RxAbort)
// 	OAM_MultiAddr_OK <= 1'b0;
//   else if(StateData)
//   begin
// 	if(ByteCntEq0)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[47:40];			//the MPCP/PAUSE/OAM has the the same mutlicast addr [47:8]
// 	else if(ByteCntEq1)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[39:32] & OAM_MultiAddr_OK;
// 	else if(ByteCntEq2)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[31:24] & OAM_MultiAddr_OK;
// 	else if(ByteCntEq3)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[23:16] & OAM_MultiAddr_OK;
// 	else if(ByteCntEq4)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[15:8] & OAM_MultiAddr_OK;
// 	else if(ByteCntEq5)
// 	  OAM_MultiAddr_OK <= Rxd == OAM_Multicast[7:0] & OAM_MultiAddr_OK;
//   end
// end

// //for unicast 
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)				//reset or rxabort or rxendfrm !
// 	UnicastOK <= 1'b0;
//   else if(StateData & ByteCntEq0)
// 	UnicastOK <= Rxd == MAC[47:40];
//   else if(StateData & ByteCntEq1)
// 	UnicastOK <= Rxd == MAC[39:32] & UnicastOK;
//   else if(StateData & ByteCntEq2)
// 	UnicastOK <= Rxd == MAC[31:24] & UnicastOK;
//   else if(StateData & ByteCntEq3)
// 	UnicastOK <= Rxd == MAC[23:16] & UnicastOK;
//   else if(StateData & ByteCntEq4)
// 	UnicastOK <= Rxd == MAC[15:8] & UnicastOK;
//   else if(StateData & ByteCntEq5)
// 	UnicastOK <= Rxd == MAC[7:0] & UnicastOK;
//   else if(RxEndFrm | RxAbort)
// 	UnicastOK <= 1'b0;
// end

// //for broadcast 
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)
// 	BroadcastOK <= 1'b0;
//   else if(StateData & ByteCntEq0)
// 	BroadcastOK <= &Rxd;						//equal to 8'hFF
//   else if(StateData & ByteCntLtEq5)				//from 1 to 5
// 	BroadcastOK <= &Rxd | BroadcastOK;
//   else if(RxEndFrm | RxAbort)
// 	BroadcastOK <= 1'b0;
// end
// //for multicast ???
// always@(posedge Rx_clk or posedge reset)
// begin
//   MulticastOK <= 1'b0;
// end

// //for RxAbort & RxEndFrm
// always@(posedge Rx_clk or posedge reset)
// begin
//   if(reset)
// 	RxAbort <= 1'b0;
//   else if(StateData & ByteCntEq6 & ~RxAddrValid)
// 	RxAbort <= 1'b1;
//   else 
// 	RxAbort <= 1'b0;					//only last for one clk
// end

// //RxEndFrm
// // always@(posedge Rx_clk or posedge reset)
// assign 			  RxEndFrm 	  = StateData & ~Rx_dv;				//this signal is not appropriate, should be sync with Rx_clk !!!
  
//////////////////// end of addr check ////////////////////

// ==================== start of CRC ====================
wire 	  [31:0]  Crc;
wire 			  CrcErr;
wire 			  enable_crc, init_crc;

assign 			  enable_crc   = Rx_dv & StateData & ~ByteCntMaxFrame;
assign 			  init_crc 	  = StateSFD | StateIdle;

crc32 crc_rx(
	.clk					(Rx_clk),
	.reset					(reset),
	.Data					(Rxd),
	.enable					(enable_crc),
	.init					(init_crc),
	.Crc					(Crc),
	.CrcErr					(CrcErr) );


//////////////////// end of CRC ////////////////////
assign 			  rx_fcs_ok   = ~CrcErr & ~Rx_dv;				//must wait Rx_dv de-asserted because ~CrcErr may asserted in the middle of frame ???


endmodule // eth_rx
